using System;
using System.Collections;
using System.Collections.Generic;

namespace Library.WebControls.Ds {
	 class Enumerator<T> : IEnumerator<T> {
		//private const string DisposeString = "{0}. Object is disposed";
		private EnumeratorNode<T> _current;
		private EnumeratorNode<T> _last;
		private EnumeratorNode<T> _root;


		public Enumerator() {
			_root = new EnumeratorNode<T>(this);
			_current = _root;
			_last = _root;
			//isDisposed = false;
		}

		public T Last {
			get { return LastNode.Value; }
		}

		public EnumeratorNode<T> LastNode {
			get {
				if (ReferenceEquals(_last, _root)) {
					throw new NullReferenceException();
				}

				return _last;
			}

			internal set { _last = value; }
		}

		public EnumeratorNode<T> CurrentNode {
			get {
				//if (isDisposed)
				//  throw new ObjectDisposedException(String.Format(DisposeString, this));
				if (ReferenceEquals(_current, _root))
					throw new NullReferenceException("Current is null. Call MoveNext first");
				return _current;
			}
		}

		#region IEnumerator<T> Members

		public T Current {
			get { return CurrentNode.Value; }
		}


		// private bool isDisposed;
		public void Dispose() {
			//Toto do nothing
			//bool canCallDispose = root.Value is IDisposable;
			//if (!isDisposed) {
			//  lock (this) {
			//    if (!isDisposed) {
			//      current = root;
			//      while (current != null) {
			//        if (canCallDispose) {
			//          ((IDisposable)current.Value).Dispose();
			//        }

			//        EnumeratorNode<T> next = current.Next;
			//        current = null;
			//        current = next;
			//      }
			//    }

			//    isDisposed = true;
			//  }
			//}
		}


		object IEnumerator.Current {
			get {
				//if (isDisposed)
				//  throw new ObjectDisposedException(String.Format(DisposeString, this));
				return Current;
			}
		}

		public bool MoveNext() {
			//if (isDisposed)
			//  throw new ObjectDisposedException(String.Format(DisposeString, this));

			if (_current.Next != null) {
				_current = _current.Next;
				return true;
			}

			return false;
		}

		public void Reset() {
			//if (isDisposed)
			//  throw new ObjectDisposedException(String.Format(DisposeString, this));
			_current = _root;
		}

		#endregion

		/// <summary>
		///  Add a node behind last node
		/// </summary>
		/// <param name="item">T item</param>
		public void AddNode(T item) {
			var next = new EnumeratorNode<T>(this);
			next.Value = item;
			_last.Next = next;
			next.Preview = _last;
			_last = next;
		}

		internal void Join(Enumerator<T> enumerator) {
			if (ReferenceEquals(enumerator._root, enumerator._last)) return;
			_last.Next = enumerator._root.Next;
			enumerator._root.Preview = _last;
			_last = enumerator._last;
			enumerator._root = _root;
		}
		internal EnumeratorNode<T> RootNode {
			get { return _root; }
		}
	}
}